package com.ruoyi.framework.aspectj;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;
import eu.bitwalker.useragentutils.UserAgent;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

/**
 * @Description: 切面实现 controller请求与返回数据的打印
 */
@Component
@Aspect
@Slf4j
public class LogRecordAspect {
    // 定义切点
    @Pointcut("execution(* com.ruoyi.business.controller..*.*(..))")
    public void excudeService() {
    }

    // 切点实现
    @Around("excudeService()")
    public Object busLogPrint(ProceedingJoinPoint pjp) throws Throwable {
        // 获取当前的用户
        String currentUserId="未知";
        try {
            LoginUser loginUser = SecurityUtils.getLoginUser();
            currentUserId = String.valueOf(loginUser.getUserId());
        } catch (Exception e) {
//            log.error("获取不到当前用户");
        }
        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        log.info("----------------------------------------------------");
        // 1.请求处理
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        assert servletRequestAttributes != null;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String uri = request.getRequestURI();
        String ip = IpUtils.getIpAddr(request);
        // 获取请求方式
        String method = request.getMethod();
        // GET
        if ("GET".equals(method)) {
            StringBuilder stringBuilder = new StringBuilder();
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                stringBuilder.append(entry.getKey()).append(" - ").append(Arrays.toString(entry.getValue())).append("\n");
            }
            // 去掉最后一个多余的回车符
            if (stringBuilder.length() != 0) {
                stringBuilder.deleteCharAt(stringBuilder.length() - 1);
                log.info(">> | GET请求开始,IP: {}, 来源: {}, userId: {}, URI: '{}', Data: \n{}",
                        ip, userAgent.getOperatingSystem().getName(), currentUserId, uri, stringBuilder);
            } else {
                log.info(">> | GET请求开始,IP: {}, 来源: {}, userId: {}, URI: '{}'",
                        ip, userAgent.getOperatingSystem().getName(), currentUserId, uri);
            }
        }
        // POST
        if ("POST".equals(method)) {
            try (BufferedReader bufferedReader = new BufferedReader(request.getReader())) {
                // 每次读取一行
                StringBuilder stringBuilder = new StringBuilder();
                String str;
                while ((str = bufferedReader.readLine()) != null) {
                    stringBuilder.append(str);
                }
                // 美化下stringBuilder这个json字符串的格式
                String prettyJsonStr = JSON.toJSONString(JSONObject.parseObject(stringBuilder.toString()), JSONWriter.Feature.PrettyFormat, JSONWriter.Feature.WriteMapNullValue);
                log.info(">> | POST请求开始,IP: {}, 来源: {}, userId: {}, URI: '{}', Data:\n {}",
                        ip, userAgent.getOperatingSystem().getName(), currentUserId, uri, prettyJsonStr);
            } catch (Exception e) {
                log.error("Post参数请求解析失败:{}", e.getMessage());
            }
        }

        // 2.返回处理
        Object result = pjp.proceed();
        try {
            String resultJson = JSON.toJSONString(result);
            if (resultJson.length() > 1000) {
                resultJson = resultJson.substring(0, 1000);
            }
            log.info("<< | 请求结束,controller返回值:{}", resultJson);
        } catch (Exception e) {
            log.error("<< | JSON解析异常:{}", e.getMessage());
        }
        log.info("----------------------------------------------------");
        return result;
    }
}

